Auto Type

타입 추론
C++ 컴파일러는 C++03에서 함수 템플릿의 인수 타입을 자동으로 추론한다.
auto 변수 타입
auto타입을 사용한다고 해도, C++의 엄격한 타입 제한은 바뀌지 않는다.
(auto 타입은 python과 같은 동적 타입과는 다르다. 파이썬에서는 a의 타입을 할당된 표현식의 타입으로 변경한다.)

C++11에서는 변수 a는 표현식의 결과 타입을 가지며, 이 후 해당 타입은 바뀌지 않는다.
자동 타입이 아닌, 한 번 정해진 뒤에는 변하지 않는 타입

auto를 통해서 초기화 되지 않은 변수 선언 불가
auto a=f(g(x, y, z)+3*x);
동일한 타입의 표현식으로 초기화되어 있는 명령문은 auto 변수를 여러개 선언할 수 있다.
auto i=2*7.5, j=std::sqrt(3.7); // 두 타입 모두 double 타입임
auto i=2*4, j=std::sqrt(3.7); // error: i는 int, j는 double
auto i=2*4, j; // error: j가 초기화 되지 않음
const 및 레퍼런스 속성을 이용해서 auto를 한정할 수 있다.
auto v=g(x, y, z); // g의 결과
auto& ri=i; // i에 대한 레퍼런스
const auto& cri=i; // i에 대한 const 레퍼런스
auto&& ur=g(x, y, z); // g의 결과에 대한 포워드 레퍼런스
v는 g가 레퍼런스를 반환하더라도, 변수 v는 레퍼런스가 아니다.
유니버설 레퍼런스 ur또한 g의 결과가 Rvalue 레퍼런스 혹은 Lvalue 레퍼런스인가에 따라
Rvalue 레퍼런스 혹은 Lvalue 레퍼런스가 된다.
표현식의 타입(decltype)
C++11 부터 decltype 키워드를 지원한다.
decltype는 함수가 반환하는 타입을 표현할 수 있다.
decltype(f(g(x, y, z)+3*x)) a=f(g(x, y, z)+3*x);
decltype은 명시적 타입이 필요한 경우, 유용하게 사용된다.
template <typename Vector1, typename Vec2>
auto operator+(const Vector1& v1, const Vector2& v2)
->vector<decltype(v1[0]+v2[0])>;
위와 같이 decltype를 이용하면, 리턴 타입 추적(Trailing Retrun Type)을 할 수 있다.
(C++11에서는 모든 함수의 리턴 타입을 선언해 주어야 함)

decltype을 사용하면, 함수 인수로 표현할 수 있으며 리턴 타입의 선언을 인수 뒤로 옮길 수 있다.

decltype은 타입 수준에서만 동작하며 인수로 전달한 표현식을 계산하지 않는다.
따라서 위에서 v1[0]을 수행하지 않고 타입만 결정한다.(빈 벡터라도 오류가 발생하지 않음)

decltype의 강력한 기능을 통해 고급 제네릭 프로그래밍 및 메타 프로그래밍에서 이점을 가짐
auto & decltype
auto는 함수 템플릿 매개변수의 규칙을 따르며, 레퍼런스 및 const 한정자를 삭제한다.
decltype은 표현식 타입을 그대로 사용한다.

만일 f가 int&를 반환하는 경우,
auto a=f(x); // a는 int 타입
decltype(f(x)) a; // a는 int& 타입
decltype(auto)
decltype에서 표현식( (f(g(x, y, z,)+3*x)) )이 길 경우, decltype(auto)를 사용해서 축약할 수 있다.
decltype(expr) v=expr;
decltype(auto) v=expr; // 동일하게 동작
자동 리턴 타입
template <typename Vector>
class value_range_vector{
using value_type=typename Vector::value_type;
using size_type=typename Vector::size_type;
public:
value_range_vector(Vector& vref, value_type minv, value_type maxv)
: vref(vref), minv(minv), maxv(maxv) {}
decltype(auto) operator[](size_type t){
decltype(auto) value=vref[i];
if(value<minv) throw too_small{};
if(value>maxv) throw too_large{};
return value;
}
private:
Vector& vref;
value_type minv, maxv;
};
int main(void){
using Vec=mtl::vector<double>;
Vec v={2.3, 8.1, 9.2};
value_range_vector<Vec> w(v, 1.0, 10.0);
decltype(auto) val=w[i];
return 0;
}
위 예제에서 val은 double& 타입이다.
만일 위의 코드에서 decltype(auto)를 auto로 변경하게 되면,
val은 double 타입이 된다.
타입 정의
typedef와 using을 사용해서 타입을 정의할 수 있다.

typedef는 C에도 존재하기 때문에 호환할 수 있다.
C++11 이후의 컴파일러에서는 using을 사용하는 것이 좋다.
typedef double value_type;
using value_type=double;
typedef double dal[10];
using dal=double[10];
typedef는 새로운 이름이 오른쪽에 위치하며, using은 왼쪽에 존재한다.

배열을 선언할 때, using을 사용하면, 배열의 타입이 하나의 조각안에 존재함
typedef float float_fun1(float, int);
using float_func1=float(float, int);
이와 같이 using 선언은 새로운 타입과 변수의 이름을 명확하게 구분한다.
템플릿 에일리어스(Template Alias)
템플릿 에일리어스는 타입 매개변수를 갖는 정의이다.
template <unsigned Order, typename Value>
class tensor{ ... };
template <typename Value>
using vector=tensor<1, Value>;
template <typename Value>
using matrix=tensor<2, Value>;
int main(void){
std::cout<<"type of vector<float> is "<<typeid(vector<float>).name()<<'\n';
std::cout<<"type of matrix<float> is "<<typeid(matrix<float>).name()<<'\n';
}
템플릿 에일리어스는 typedef로는 불가능하지만, using을 사용하면 쉽게 만들 수 있다.

typedef는 템플릿을 지원하지 않지만, using은 템플릿을 지원함